from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QPointF, QVariantAnimation, QPropertyAnimation, Qt , QRectF
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QMouseEvent, QPaintEvent, QResizeEvent

class WBSwitchButton(QWidget):
    sigEnableChanged = pyqtSignal(bool)
    sigSwitchChanged = pyqtSignal(bool)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._on_off = False
        self._enable = True
        self._precision_click_flag = False
        self._wait_sig_model = True
        self._animation_on_off = True
        self._hover = False

        self._button_color = QColor(Qt.white)
        self._back_color = QColor(Qt.red)
        self._edge_color = QColor(Qt.transparent)
        self._button_rect = QRectF()
        self._radius = 8

        self._animation_period = 200
        self._right_pos = QPointF()
        self._left_pos = QPointF()
        self._back_on_color = QColor(81, 194, 155)
        self._back_off_color = QColor(100, 100, 100)

    def get_switch(self):
        return self._on_off

    def set_switch(self, onoff):
        if self._wait_sig_model or self._on_off == onoff:
            return
        self._on_off = onoff
        self.sigSwitchChanged.emit(self._on_off)
        # 调试输出目标颜色
        target_color = self._back_on_color if onoff else self._back_off_color
        # 颜色动画
        self._color_anim = QPropertyAnimation(self, b"p_back_color")
        self._color_anim.setDuration(self._animation_period)
        self._color_anim.setStartValue(self._back_color)
        self._color_anim.setEndValue(target_color)
        self._color_anim.start()
        # 位置动画
        self._pos_anim = QVariantAnimation(self)
        self._pos_anim.setDuration(self._animation_period)
        self._pos_anim.setStartValue(self._button_rect.topLeft())
        self._pos_anim.setEndValue(self._right_pos if onoff else self._left_pos)
        self._pos_anim.valueChanged.connect(self._update_button_position)
        self._pos_anim.start()

    def _update_button_position(self, value):
        self._button_rect.moveTo(value)
        self.update()

    def set_switch_for_wait_model(self, onoff):
        if not self._wait_sig_model:
            return
        if self._on_off == onoff:
            pos_animation = QVariantAnimation(self)
            pos_animation.setDuration(self._animation_period)
            pos_animation.setStartValue(self._right_pos if not self._on_off else self._left_pos)
            pos_animation.setEndValue(self._right_pos if self._on_off else self._left_pos)
            pos_animation.valueChanged.connect(lambda value: self._update_button_position(value))
            pos_animation.start(QVariantAnimation.DeleteWhenStopped)
            return
        
        self._on_off = onoff
        self.sigSwitchChanged.emit(self._on_off)
        
        color_animation = QPropertyAnimation(self, b"p_back_color")
        color_animation.setDuration(self._animation_period)
        color_animation.setStartValue(self._back_color)
        color_animation.setEndValue(self._back_on_color if self._on_off else self._back_off_color)
        color_animation.valueChanged.connect(lambda: self.update())
        color_animation.start(QPropertyAnimation.DeleteWhenStopped)

    def set_enabled(self, enable):
        super().setEnabled(enable)
        self._enable = enable
        self.sigEnableChanged.emit(self._enable)
        self.update()

    def get_enabled(self):
        return self._enable

    def set_animation_period(self, period):
        self._animation_period = period

    def set_precision_click(self, flag):
        self._precision_click_flag = flag

    def set_wait_model(self, flag):
        self._wait_sig_model = flag

    def set_button_color(self, color):
        self._button_color = color
        self.update()

    def set_back_on_color(self, color):
        self._back_on_color = color
        self.update()

    def set_back_off_color(self, color):
        self._back_off_color = color
        self.update()

    def set_edge_color(self, color):
        self._edge_color = color
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setPen(Qt.NoPen)

        # 将 QRect 转换为 QRectF
        self.Rect = QRectF(self.rect())
        
        # 绘制边缘
        path = QPainterPath()
        path.addRect(self.Rect)
        path.addRoundedRect(self.Rect, self._radius, self._radius)
        path.setFillRule(Qt.OddEvenFill)
        painter.setBrush(self._edge_color)  # 使用边缘颜色
        painter.drawPath(path)

        # 绘制背景
        painter.setBrush(self._back_color)
        painter.drawRoundedRect(self.Rect, self._radius, self._radius)

        # 绘制按钮
        painter.setBrush(self._button_color)
        painter.drawEllipse(self._button_rect)

        painter.setBrush(Qt.NoBrush)
        color = QColor(Qt.black)
        count = (self.height() - self._button_rect.height()) / 2
        step_color = (0.15 - 0.0) / count
        for i in range(int(self._button_rect.height() / 2 + 1), int(self.height() / 2)):
            color.setAlphaF(0.15 - step_color * (i - self._button_rect.height() / 2))
            painter.setPen(color)
            painter.drawEllipse(self._button_rect.center(), i, i)

        if not self._enable:
            disable = QColor(Qt.black)
            disable.setAlphaF(0.5)
            painter.setBrush(disable)
            painter.drawRoundedRect(self.Rect, self._radius, self._radius)

    def resizeEvent(self, event):
        size = min(self.width(), self.height())
        self._radius = size / 2
        width = size * 3 / 4
        border = (size - width) / 2
        self._left_pos = QPointF(border, border)
        self._right_pos = QPointF(self.width() - border - width, border)
        self._button_rect.setWidth(width)
        self._button_rect.setHeight(width)
        self._button_rect.moveTo(self._right_pos if self._on_off else self._left_pos)
        self._back_color = self._back_on_color if self._on_off else self._back_off_color
        self.update()

    def mouseReleaseEvent(self, event):
        if self._wait_sig_model:
            pos_animation = QVariantAnimation(self)
            pos_animation.setDuration(self._animation_period)
            pos_animation.setStartValue(self._right_pos if self._on_off else self._left_pos)
            pos_animation.setEndValue(self._left_pos if self._on_off else self._right_pos)
            pos_animation.valueChanged.connect(lambda value: self._update_button_position(value))
            pos_animation.start(QVariantAnimation.DeleteWhenStopped)
            return
        
        if not self._enable:
            return
        
        if self._button_rect.contains(event.pos()) or not self._precision_click_flag:
            self.set_switch(not self._on_off)

    def enterEvent(self, event):
        self._hover = True

    def leaveEvent(self, event):
        self._hover = False

    @pyqtProperty(QColor)
    def p_back_color(self):
        return self._back_color

    @p_back_color.setter
    def p_back_color(self, color):
        if self._back_color != color:
            self._back_color = color
            self.update()  # 必须调用！